//
// Created by wk on 2023/12/5.
//

#ifndef AUDIOEFFECT_AUDIOEFFECT_H
#define AUDIOEFFECT_AUDIOEFFECT_H

#include <mutex>

#define M_PI 3.1415926535897932384626433832795

namespace audio_effect {

    class AudioEffect {

    };


    /**
	 * 低通滤波
	 */
    class LowEffect {

    public:

        LowEffect(float sample_rate, double center_freq) {
            this->sample_rate = sample_rate;
            this->center_freq = center_freq;
            init();
        }

        LowEffect(float sample_rate, double center_freq, double q) {
            this->sample_rate = sample_rate;
            this->center_freq = center_freq;
            this->Q = q;
            init();
        }


        void init() {
            Q = (Q == 0) ? 1e-9 : Q;

            double ov = 2 * M_PI * center_freq / sample_rate;
            double sn = sin(ov);
            double cs = cos(ov);
            double alpha = sn / (2 * Q);

            b0 = (1 - cs) / 2;
            b1 = 1 - cs;
            b2 = (1 - cs) / 2;
            a0 = 1 + alpha;
            a1 = -2 * cs;
            a2 = 1 - alpha;
            gcompute();
        }

        /**
	 * 过滤
	 *
	 * @param x
	 * @return
	 */
        double filter(double x) {
            y = b0 * x + b1 * x1 + b2 * x2 - a1 * y1 - a2 * y2;
            x2 = x1;
            x1 = x;
            y2 = y1;
            y1 = y;
            return y;
        }

    private:
        /**
	 * 计算
	 */
        void gcompute() {
            // a0归一化为1
            b0 /= a0;
            b1 /= a0;
            b2 /= a0;
            a1 /= a0;
            a2 /= a0;
        }

    private:
        /**
	 * 采样率
	 */
        float sample_rate = 44100.0f;
/**
	 * 中心频率
	 */
        double center_freq = 0.0f;

        /**
       * Q值
       */double Q = 1;

        double b0, b1, b2, a0, a1, a2;
        double x1, x2, y, y1, y2;
    };


    /**
      * 高通滤波
      */
    class HightEffect {

    public:

        HightEffect(float sample_rate, double center_freq) {
            this->sample_rate = sample_rate;
            this->center_freq = center_freq;
            init();
        }

        HightEffect(float sample_rate, double center_freq, double q) {
            this->sample_rate = sample_rate;
            this->center_freq = center_freq;
            this->Q = q;
            init();
        }


        void init() {
            Q = (Q == 0) ? 1e-9 : Q;

            double ov = 2 * M_PI * center_freq / sample_rate;
            double sn = sin(ov);
            double cs = cos(ov);
            double alpha = sn / (2 * Q);

            b0 = (1 + cs) / 2;
            b1 = -(1 + cs);
            b2 = (1 + cs) / 2;
            a0 = 1 + alpha;
            a1 = -2 * cs;
            a2 = 1 - alpha;

            gcompute();
        }

        /**
	 * 过滤
	 *
	 * @param x
	 * @return
	 */
        double filter(double x) {
            y = b0 * x + b1 * x1 + b2 * x2 - a1 * y1 - a2 * y2;
            x2 = x1;
            x1 = x;
            y2 = y1;
            y1 = y;
            return y;
        }

    private:
        /**
	 * 计算
	 */
        void gcompute() {
            // a0归一化为1
            b0 /= a0;
            b1 /= a0;
            b2 /= a0;
            a1 /= a0;
            a2 /= a0;
        }

    private:
        /**
	 * 采样率
	 */
        float sample_rate = 44100.0f;
/**
	 * 中心频率
	 */
        double center_freq = 0.0f;

        /**
       * Q值
       */double Q = 1;

        double b0, b1, b2, a0, a1, a2;
        double x1, x2, y, y1, y2;
    };

    class BassEffect {



    public:
        BassEffect(float samplerate);
        void process(float *inBlock, float *outBlock,size_t block_len);

        void setBass(float db);
    private:
        float samplerate;
        double bass;
        double gain;
        double hzBass;
        double slope;
        double a0Bass, a1Bass, a2Bass, b0Bass, b1Bass, b2Bass;
        double xn1Bass, xn2Bass, yn1Bass, yn2Bass;

        bool  update = false;


        /**
         * 外部设置的
         */
        double mBass = 0.0f;
        double mGain = 0.0f;

    protected:
        float doFilter(BassEffect &data, float in);


    };


    const double pi = 3.14159265358979323846;

// IIR低通滤波器
    class LowPassFilter {
    public:
        LowPassFilter(double sampleRate, double cutoffFreq, double damping) {
            double alpha = damping * (1 - cos(2 * pi * cutoffFreq / sampleRate));
            b0 = alpha;
            b1 = 1 - alpha;
            b2 = 0;
            a1 = alpha;
            a2 = (1 - damping) * (1 - damping);
            y1 = 0;
            y2 = 0;
        }

        void process(float *inBlock, float *outBlock,size_t block_len)
        {
            for(int i = 0; i< block_len;i++)
            {
                outBlock[i] =  process((double)inBlock[i]);
            }
        }

    private:
        double process(double x) {
            double y = b0 * x + b1 * y1 + b2 * y2 - a1 * y1 - a2 * y2;
            y2 = y1;
            y1 = y;
            return y;
        }

    private:
        double b0, b1, b2, a1, a2;
        double y1, y2;
    };




    class VirtualBass{
    public:
        VirtualBass();
        void init();

        void process(float *inBlock, float *outBlock,size_t block_len);

        void setStrength(double s)
        {
//            if(s<0.5)
//            {
//                strength = 0.5;
//            }
//            if(s>3.0)
//            {
//                s = 3.0;
//            }
            this->strength = s;
        }

    private:
    private:
        double process(double x);

        const double Q = 0.707;

        double sample_rate=44100;
        double cutoff = 200;
        double strength = 0.5;

        double a[3] = {0}, m[3] = {0.0f}, cf[2] = {0.0f};
    };



    class EqualizerEffect{

    public:
        EqualizerEffect(int i_rate);

        ~EqualizerEffect();

        void init(int i_rate );

        void process(float *inBlock, float *outBlock,size_t block_len);

        void update(int bandIndex, float  db);

        void updatePreset(const char* preset);

        void updateAmp(float db);
    private:
        /* Filter static config */
        int i_band;
        float *f_alpha = nullptr;
        float *f_beta = nullptr;
        float *f_gamma = nullptr;

        /* Filter dyn config */
        float *f_amp = nullptr;   /* Per band amp */
        float f_gamp = 0.0f;   /* Global preamp */
        bool b_2eqz = false;
        /* Filter state */
        float x[32][2];
        float y[32][128][2];

        /* Second filter state */
        float x2[32][2];
        float y2[32][128][2];

        std::mutex mLock;
    };


#define IS_DENORMAL(d) (abs(d) < DBL_MIN)

    class BiQuad
    {
    public:
        enum Type
        {
            LOW_PASS, HIGH_PASS, BAND_PASS, NOTCH, ALL_PASS, PEAKING, LOW_SHELF, HIGH_SHELF
        };

        BiQuad() {}
        BiQuad(Type type, double dbGain, double freq, double srate, double bandwidthOrQOrS, bool isBandwidthOrS);

        void removeDenormals();

        double process(double sample);

        void setCoefficients(double ain[], const double& a0in);

        double gainAt(double freq, double srate);

    private:
        double a[4];
        double a0;

        double x1, x2;
        double y1, y2;
    };



    void test();
}


#endif //AUDIOEFFECT_AUDIOEFFECT_H
